package cn.good.yan.service.t1;

import cn.good.yan.service.t1.myLock.DistributedLockFactory;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.locks.Lock;

/**
 * 1 测试 Redis - 分布式
 *      完善的支持可重入锁、看门狗机制
 *      但只适合单机的Redis分布式锁，如果支持多台Redis机器，保证加锁，在 redis2LockB 项目 t1
 * @author shengren.yan
 * @create 2023-12-04
 */
@Service
@Slf4j
public class OrderService2 {

    // 判断哪台机器
    @Value("${server.port}")
    private String port;

    @Resource
    private RedisTemplate redisTemplate;

    @Autowired
    private DistributedLockFactory distributedLockFactory;

    @Autowired
    private Redisson redisson;

    /**
     * 终极  分布式锁 加锁和解锁都是 使用 Lua 脚本 - 保证原子性，并支持可重入锁、增加监控看门狗，自动续期
     *
     * @return
     */
    public String sale() {
        String retMessage = "";
        Lock redisLock = distributedLockFactory.getDistributedLock("redis");
        // 加锁
        redisLock.lock();
        try {
            //1 查询库存信息  该 sale100 的key在redis中有100个库存
            String result = (String) redisTemplate.opsForValue().get("sale100");
            //2 判断库存是否足够
            Integer num = result == null ? 0 : Integer.parseInt(result);
            //3 扣减库存
            if (num > 0) {
                redisTemplate.opsForValue().set("sale100", String.valueOf(--num));
                retMessage = "成功卖出一个商品，库存剩余: " + num;
                System.out.println(retMessage);
            } else {
                retMessage = "商品卖完了，o(╥﹏╥)o";
            }
        } finally {
            // 解锁
            redisLock.unlock();
        }
        return retMessage + "\t" + "服务端口号：" + port;
    }

    // 使用Redisson 作为分布式锁
    public String saleB() {
        String retMessage = "";
        RLock redissonLock = redisson.getLock("xxRedisLock");
        // 加锁
        redissonLock.lock();
        try {
            //1 查询库存信息  该 sale100 的key在redis中有100个库存
            String result = (String) redisTemplate.opsForValue().get("sale100");
            //2 判断库存是否足够
            Integer num = result == null ? 0 : Integer.parseInt(result);
            //3 扣减库存
            if (num > 0) {
                redisTemplate.opsForValue().set("sale100", String.valueOf(--num));
                retMessage = "成功卖出一个商品，库存剩余: " + num;
                System.out.println(retMessage);
            } else {
                retMessage = "商品卖完了，o(╥﹏╥)o";
            }
            System.out.println(retMessage);
        } finally {
            // 改进点，只能删除属于自己的 key，不能删除别人的
            if (redissonLock.isLocked() && redissonLock.isHeldByCurrentThread()){
                redissonLock.unlock();
            }
        }
        return retMessage + "\t" + "服务端口号：" + port;
    }

}
